package simpletestbed;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import simpletestbed.core.SimpleTestBedClient;

public class RemoteSingleCaseTestBed extends RemoteTestBed{
	
	public RemoteSingleCaseTestBed(String configFileName) throws IOException {
		super(configFileName);
	}
	
	public RemoteSingleCaseTestBed(String configFileName, String localBinPath) throws IOException {
		super(configFileName, localBinPath);
	}
	
	@Override
	public TestResult[] execute() {
		try {
			int numMachines = this.remoteServers.size();
			if (numMachines == 0) {
				throw new Error("No remote server configured !");
			}
			
			TestResult[] averageResults = new TestResult[this.testCases.size()];
			this.avgRuntimes = new double[this.testCases.size()];
			this.maxMemUsage = new double[this.testCases.size()];
			RemoteMonitor[] monitors = new RemoteMonitor[numMachines];
			int[] monitorCaseIndexes = new int[numMachines];
			for (int machineId=0; machineId<monitors.length; machineId++) {
				monitors[machineId] = null;
				
				// Invoke SimpleTestBed client to send command
				String serverHost = this.remoteServers.get(machineId);
				SimpleTestBedClient client = new SimpleTestBedClient(serverHost);
				// Send java classes
				client.execSendClasses("clientcp" + machineId, this.localBinPath);
			}
			
			for (int caseIdx = 0; caseIdx<this.testCases.size(); caseIdx++) {
				// Find a free monitor
				int freeMachineId = -1;
				while (freeMachineId == -1) {
					for (int machineId=0; machineId<monitors.length; machineId++) {
						RemoteMonitor monitor = monitors[machineId];
						if (monitor == null ) {
							freeMachineId = machineId;
							break;
						}
						else {
							if (monitor.isAlive() == false) { // This monitor has finished
								int itsCaseIdx = monitorCaseIndexes[machineId];
								// Collect its results
								averageResults[itsCaseIdx] = monitor.getResult()[0];
								this.avgRuntimes[itsCaseIdx] = monitor.getRuntime()[0];
								this.maxMemUsage[itsCaseIdx] = monitor.getMaxMemUsage();
								// Assign this one to be free
								freeMachineId = machineId;
								// Erase this monitor
								monitors[machineId] = null;
								monitorCaseIndexes[machineId] = -1;
								break;
							}
						}
					}
				}
				List<TestCase> subCases = new ArrayList<TestCase>(1);
				subCases.add(this.testCases.get(caseIdx));
				String serverHost = this.remoteServers.get(freeMachineId);
				monitors[freeMachineId] = new RemoteMonitor(serverHost, freeMachineId, subCases, 
						this.checkMemUsage, this.threadTimeOut);
				monitorCaseIndexes[freeMachineId] = caseIdx;
				monitors[freeMachineId].start();
			}
			
			// Wait for all monitors finish
			for (int machineId=0; machineId<monitors.length; machineId++) {
				RemoteMonitor monitor = monitors[machineId];
				if (monitor == null ) {
					continue;
				}
				monitor.join();
				int itsCaseIdx = monitorCaseIndexes[machineId];
				// Collect its results
				averageResults[itsCaseIdx] = monitor.getResult()[0];
				this.avgRuntimes[itsCaseIdx] = monitor.getRuntime()[0];
				this.maxMemUsage[itsCaseIdx] = monitor.getMaxMemUsage();
				// Erase this monitor
				monitors[machineId] = null;
				monitorCaseIndexes[machineId] = -1;
			}
			
			return averageResults;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	}
	


}
